using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using MSRI.HelperClasses;

namespace MSRI.SmsSessions
{
    public delegate SmsResponseClass SmsSessionDelegate(object SessionData, SmsClass SmsItem);
    public enum MenuItemEnum { CustomFunction, CustomString, NestedMenuItem };
    public class SmsMenu
    {
        private List<string> _stateList;
        private List<SmsMenuItem> _Items;
        private object _menuData;
        private int _moreCount = 0;
        private string _MoreKey;
        private string _header;
        private string _footer;
        private string _ErrorString;
        private int _MaxSmsBodyLength;
        private string _keyTextSeparator;

        public string KeyTextSeparator
        {
            get { return _keyTextSeparator; }
            set { _keyTextSeparator = value; }
        }

        public String ErrorMessage
        {
            get { return _ErrorString; }
            set { _ErrorString = value; }
        }

        public int MaxSmsBodyLength
        {
            get { return _MaxSmsBodyLength; }
            set { _MaxSmsBodyLength = value; }
        }

        public List<string> StateList
        {
            get { return _stateList; }
            set { _stateList = value; }
        }
        public SmsMenu()
        {
            _moreCount = 0;
            _menuData = null;
            _stateList = new List<string>();
            _Items = new List<SmsMenuItem>();
            _MoreKey = null;
            _header = null;
            _footer = null;
            _ErrorString = "Error:Invalid Option";
            _MaxSmsBodyLength = 160;
            _keyTextSeparator = "-";
        }

        public int MoreCount
        {
            get { return _moreCount; }
        }

        public List<SmsMenuItem> Items
        {
            get { return _Items; }
        }
        public SmsMenu(SmsMenu Menu)
        {
            _moreCount = Menu.MoreCount;
            _menuData = null;
            _stateList = new List<string>(Menu.StateList);
            _Items = new List<SmsMenuItem>(Menu.Items);
            _MoreKey = Menu.MoreKey;
            _header = Menu.Header;
            _footer = Menu.Footer;
            _ErrorString = Menu.ErrorMessage;
            _MaxSmsBodyLength = Menu.MaxSmsBodyLength;
            _keyTextSeparator = Menu.KeyTextSeparator;
        }
        private bool ValidKey(string CheckKey)
        {
            if (_Items == null || CheckKey==null || _MoreKey == CheckKey.Trim())
                return false;
            for (int i = 0; i < _Items.Count; i++)
            {
                if (_Items[i].Key == CheckKey.Trim() || _Items[i].AltKey == CheckKey.Trim())
                    return false;
            }
            return true;
        }
        public string Header
        {
            get { return _header; }
            set { _header = value; }
        }

        public string Footer
        {
            get { return _footer; }
            set { _footer = value; }
        }

        public bool ClearSubMenuItems()
        {
            if (_Items != null)
            {
                _Items.Clear();
                _moreCount = 0;
                return true;
            }
            return false;
        }

        public bool AddSubMenuItem(SmsMenuItem MenuItem)
        {
            if (_Items == null)
                _Items = new List<SmsMenuItem>();
            if (ValidKey(MenuItem.Key) && (MenuItem.AltKey == null || ValidKey(MenuItem.AltKey)))
                _Items.Add(MenuItem);
            else
                throw new Exception("Error: The Key or AltKey you are trying to register is already in use");
            return true;
        }

        public SmsMenuItem this[string MenuKey]
        {
            get
            {
                if (_Items == null || MenuKey == null || MenuKey.Trim().Length == 0)
                    return null;
                for (int i = 0; i < _Items.Count; i++)
                {
                    if (_Items[i].Key == MenuKey || _Items[i].AltKey == MenuKey)
                        return _Items[i];
                }
                return null;
            }
        }

        public string MoreKey
        {
            get { return _MoreKey; }
            set
            {
                if (value == null || ValidKey(value))
                    _MoreKey = value;
                else
                    throw new Exception("Error:Invalid Menu Key or Key already in use");
            }
        }

        public SmsMenuItem CurrentMenuItem
        {
            get
            {
                if (_stateList == null || _stateList.Count == 0 || _Items == null)
                    return null;
                SmsMenuItem MenuItem = this[_stateList[0]];
                for (int i = 1; i < _stateList.Count; i++)
                {
                    MenuItem = MenuItem[_stateList[i]];
                    if (MenuItem == null)
                        break;
                }
                return MenuItem;
            }
        }

        public object SmsMenuData
        {
            get { return _menuData; }
            set { _menuData = value; }
        }

        private string GetString(int MaxLength, int start)
        {
            string rstr = "";
            MaxLength -= (_footer == null ? 0 : _footer.Length); // -(_header == null ? 0 : (_header + Environment.NewLine).Length);
            int i = start;
            rstr = _header == null ? "" : (_header + Environment.NewLine);
            string MoreString = _MoreKey == null ? "" : string.Format("{0}{1}More\n", _MoreKey,_keyTextSeparator);
            for (i = start; i < _Items.Count && rstr.Length < MaxLength; i++)
            {
                string ItemString = string.Format("{0}{2}{1}\n", _Items[i].Key, _Items[i].Text,_keyTextSeparator);
                if (i == _Items.Count - 1)
                {
                    if (rstr.Length + ItemString.Length > MaxLength)
                    {
                        _moreCount = i;
                        rstr += MoreString;
                        break;
                    }
                    else
                    {
                        _moreCount = i + 1;
                        rstr += ItemString;
                    }
                }
                else
                {
                    if (rstr.Length + ItemString.Length + MoreString.Length > MaxLength)
                    {
                        _moreCount = i;
                        rstr += MoreString;
                        break;
                    }
                    else
                        rstr += ItemString;
                }
            }
            rstr += _footer == null ? "" : _footer;
            return rstr;
        }

        public string ToString(int MaxLength)
        {
            return GetString(MaxLength, 0);
        }

        public string More(int MaxLength)
        {
            if (_Items == null || _moreCount == _Items.Count)
                return _ErrorString;
            else
                return GetString(MaxLength, _moreCount);
        }

        public SmsResponseClass ProcessMessage(Object SessionData, SmsClass SmsItem)
        {
            SmsMenuItem MenuItem = CurrentMenuItem;
            SmsResponseClass response;
            if (MenuItem == null)
            {
                // At Start of Menu
                if (SmsItem.Body == _MoreKey)
                    response = new SmsResponseClass(new SmsClass(SmsItem.Number, this.More(MaxSmsBodyLength)));
                else if (this[SmsItem.Body] != null)
                {
                    MenuItem = this[SmsItem.Body];
                    if (MenuItem.Type == MenuItemEnum.CustomString)
                    {
                        response = new SmsResponseClass(new SmsClass(SmsItem.Number, MenuItem.ResponseString));
                        response.SessionState = MenuItem.ResponseSessionState;
                    }
                    else if (MenuItem.Type == MenuItemEnum.CustomFunction)
                    {
                        _stateList.Add(SmsItem.Body);
                        response = MenuItem.CallCustomFunction(SmsItem);
                    }
                    else
                    {
                        _stateList.Add(SmsItem.Body);
                        _moreCount = 0;
                        response = new SmsResponseClass(new SmsClass(SmsItem.Number, MenuItem.ToString(MaxSmsBodyLength)));
                    }

                }
                else
                    response = new SmsResponseClass(new SmsClass(SmsItem.Number, this.ToString(MaxSmsBodyLength)));
            }
            else
            {
                // Somewhere in nested Menu or MenuItem with CustomFunction
                if (MenuItem.Type == MenuItemEnum.CustomString)
                { // this should never happen
                    response = new SmsResponseClass(new SmsClass(SmsItem.Number, MenuItem.ResponseString));
                    response.SessionState = MenuItem.ResponseSessionState;
                }
                else if (MenuItem.Type == MenuItemEnum.CustomFunction)
                { // Looping into the same CustomFunction
                    response = MenuItem.CallCustomFunction(SmsItem);
                }
                else
                { // 
                    if (SmsItem.Body == MenuItem.MoreKey)
                    {
                        response = new SmsResponseClass(new SmsClass(SmsItem.Number, MenuItem.More(MaxSmsBodyLength)));
                    }
                    else if (SmsItem.Body == MenuItem.BackKey)
                    {
                        _stateList.RemoveAt(_stateList.Count - 1);
                        MenuItem = CurrentMenuItem;
                        response = new SmsResponseClass(new SmsClass(SmsItem.Number, MenuItem.ToString(MaxSmsBodyLength)));
                    }
                    else if (SmsItem.Body == MenuItem.HomeKey)
                    {
                        _stateList.Clear();
                        response = new SmsResponseClass(new SmsClass(SmsItem.Number, this.ToString(MaxSmsBodyLength)));
                    }
                    else if (MenuItem[SmsItem.Body] != null)
                    { // Selected to go one level deep
                        _stateList.Add(SmsItem.Body);
                        MenuItem = MenuItem[SmsItem.Body];
                        if (MenuItem.Type == MenuItemEnum.CustomString)
                        {
                            response = new SmsResponseClass(new SmsClass(SmsItem.Number, MenuItem.ResponseString));
                            response.SessionState = MenuItem.ResponseSessionState;
                        }
                        else if (MenuItem.Type == MenuItemEnum.CustomFunction)
                        {
                            _stateList.Add(SmsItem.Body);
                            response = MenuItem.CallCustomFunction(SmsItem);
                        }
                        else
                        {
                            _stateList.Add(SmsItem.Body);
                            _moreCount = 0;
                            response = new SmsResponseClass(new SmsClass(SmsItem.Number, MenuItem.ToString(MaxSmsBodyLength)));
                        }
                    }
                    else
                        response = new SmsResponseClass(new SmsClass(SmsItem.Number, MenuItem.ErrorMessage));
                }
            }
            if (response.SessionState == ResponseSessionStateEnum.Reset)
            {
                _stateList.Clear();
                _moreCount = 0;
            }
            return response;
        }
    }
    public class SmsMenuItem
    {
        private string _text;
        private string _key;
        private string _AltKey;
        private MenuItemEnum _type;
        private string _responseString;
        private SmsSessionDelegate _SessionDelegate;
        private List<SmsMenuItem> _Items;
        private string _header;
        private string _footer;
        private object _menuData;
        private int _moreCount;
        private string _MoreKey;
        private string _BackKey;
        private string _HomeKey;
        private string _ErrorString;
        private ResponseSessionStateEnum _ResponseSessionState;
        private string _keyTextSeparator;

        public string KeyTextSeparator
        {
            get { return _keyTextSeparator; }
            set { _keyTextSeparator = value; }
        }

        public SmsMenuItem()
        {
            _text = "";
            _key = null;
            _AltKey = null;
            _type = MenuItemEnum.CustomString;
            _responseString = "";
            _header = null;
            _footer = null;
            _menuData = null;
            _moreCount = 0;
            _MoreKey = null;
            _BackKey = null;
            _HomeKey = null;
            _Items = null;
            _ErrorString = "";
            _ResponseSessionState = ResponseSessionStateEnum.Ignore;
            _keyTextSeparator = "-";
        }

        public int MoreCount
        {
            get { return _moreCount; }
        }

        public ResponseSessionStateEnum ResponseSessionState
        {
            get { return _ResponseSessionState; }
            set { _ResponseSessionState = value; }
        }
        public SmsMenuItem(string MenuKey, string MenuText)
        {
            _text = MenuText;
            _key = MenuKey;
            _AltKey = null;
            _type = MenuItemEnum.CustomString;
            _responseString = "";
            _header = null;
            _footer = null;
            _menuData = null;
            _moreCount = 0;
            _MoreKey = null;
            _BackKey = null;
            _HomeKey = null;
            _Items = null;
            _ErrorString = "";
            _ResponseSessionState = ResponseSessionStateEnum.Ignore;
            _keyTextSeparator = "-";
        }

        public SmsMenuItem(SmsMenuItem Item)
        {
            _text = Item.Text;
            _key = Item.Key;
            _AltKey = Item.AltKey;
            _type = Item.Type;
            _responseString = Item.ResponseString;
            _header = Item.Header;
            _footer = Item.Footer;
            _menuData = null;
            _moreCount = Item.MoreCount;
            _MoreKey = Item.MoreKey;
            _BackKey = Item.BackKey;
            _HomeKey = Item.HomeKey;
            _Items = Item.Items;
            _ErrorString = Item.ErrorMessage;
            _ResponseSessionState = Item.ResponseSessionState;
            _keyTextSeparator = Item.KeyTextSeparator;
        }

        public List<SmsMenuItem> Items
        {
            get { return _Items; }
        }

        public SmsSessionDelegate SessionDelegate
        {
            get { return _SessionDelegate; }
        }

        public String Text
        {
            get { return _text; }
            set { _text = value; }
        }

        public String ErrorMessage
        {
            get { return _ErrorString; }
            set { _ErrorString = value; }
        }

        public string Key
        {
            get { return _key; }
            set
            {
                if (value != null)
                    _key = value.Trim();
                else
                    _key = "";
            }
        }

        public string AltKey
        {
            get { return _AltKey; }
            set { _AltKey = value; }
        }

        public string MoreKey
        {
            get { return _MoreKey; }
            set
            {
                if (value == null || ValidKey(value))
                    _MoreKey = value;
                else
                    throw new Exception("Error:Invalid Menu Key or Key already in use");
            }
        }

        public string BackKey
        {
            get { return _BackKey; }
            set
            {
                if (value == null || ValidKey(value))
                    _BackKey = value;
                else
                    throw new Exception("Error:Invalid Menu Key or Key already in use");
            }
        }

        public string HomeKey
        {
            get { return _HomeKey; }
            set
            {
                if (value == null || ValidKey(value))
                    _HomeKey = value;
                else
                    throw new Exception("Error:Invalid Menu Key or Key already in use");
            }
        }


        public MenuItemEnum Type
        {
            get { return _type; }
            set { _type = value; }
        }

        public String ResponseString
        {
            get { return _responseString; }
            set
            {
                if (_responseString != null)
                {
                    _type = MenuItemEnum.CustomString;
                    _responseString = value;
                }
                else
                    _responseString = null;
            }
        }

        public string Header
        {
            get { return _header; }
            set { _header = value; }
        }

        public string Footer
        {
            get { return _footer; }
            set { _footer = value; }
        }

        public Object MenuData
        {
            get { return _menuData; }
            set { _menuData = value; }
        }

        public void AttachCustomFuntion(SmsSessionDelegate FunctionName)
        {
            _SessionDelegate = new SmsSessionDelegate(FunctionName);
            _type = MenuItemEnum.CustomFunction;
        }


        public SmsResponseClass CallCustomFunction(SmsClass SmsItem)
        {
            if (_SessionDelegate != null)
               return _SessionDelegate(_menuData, SmsItem);
           return null;
        }

        private string GetString(int MaxLength, int start)
        {
            string rstr = "";
            MaxLength -= (_footer == null ? 0 : _footer.Length); // -(_header == null ? 0 : (_header + Environment.NewLine).Length);
            if (_type == MenuItemEnum.CustomFunction)
                return MenuItemEnum.CustomFunction.ToString();
            else if (_type == MenuItemEnum.CustomString)
                return MenuItemEnum.CustomString.ToString();
            else if (_type == MenuItemEnum.NestedMenuItem)
            {
                int i = start;
                rstr = _header == null ? "" : (_header + Environment.NewLine);
                string MoreString = _MoreKey == null ? "" : string.Format("{0}{1}More\n", _MoreKey,_keyTextSeparator);
                for (i = start; i < _Items.Count && rstr.Length < MaxLength; i++)
                {
                    string ItemString = string.Format("{0}{2}{1}\n", _Items[i]._key, _Items[i]._text,_keyTextSeparator);
                    if (i == _Items.Count - 1)
                    {
                        if (rstr.Length + ItemString.Length > MaxLength)
                        {
                            _moreCount = i;
                            rstr += MoreString;
                            break;
                        }
                        else
                        {
                            _moreCount = i + 1;
                            rstr += ItemString;
                        }
                    }
                    else
                    {
                        if (rstr.Length + ItemString.Length + MoreString.Length > MaxLength)
                        {
                            _moreCount = i;
                            rstr += MoreString;
                            break;
                        }
                        else
                            rstr += ItemString;
                    }
                }
                rstr += _footer == null ? "" : _footer;
            }
            else
                return _ErrorString;
            return rstr;
        }

        public string ToString(int MaxLength)
        {
            return GetString(MaxLength, 0);
        }

        public string More(int MaxLength)
        {
            if (_Items == null || _moreCount == _Items.Count)
                return _ErrorString;
            else
                return GetString(MaxLength, _moreCount);
        }

        private bool ValidKey(string CheckKey)
        {
            if (CheckKey == null || CheckKey.Trim().Length == 0 ||
                CheckKey.Trim() == _MoreKey || CheckKey.Trim() == _BackKey ||
                CheckKey.Trim() == _HomeKey)
                return false;
            if (_type != MenuItemEnum.NestedMenuItem || _Items != null)
                return true;
            for (int i = 0; i < _Items.Count; i++)
            {
                if (_Items[i].Key == CheckKey.Trim() || _Items[i].AltKey == CheckKey.Trim())
                    return false;
            }
            return true;
        }

        public bool ClearSubMenuItems()
        {
            if (_Items != null)
            {
                _Items.Clear();
                _moreCount = 0;
                return true;
            }
            return false;
        }

        public bool AddSubMenuItem(SmsMenuItem MenuItem)
        {
            if (_Items == null)
                _Items = new List<SmsMenuItem>();
            if (ValidKey(MenuItem._key) && (MenuItem._AltKey == null || ValidKey(MenuItem._AltKey)))
                _Items.Add(MenuItem);
            else
                throw new Exception("Error: The Key or AltKey you are trying to register is already in use");
            _type = MenuItemEnum.NestedMenuItem;
            return true;
        }

        public SmsMenuItem this[string MenuKey]
        {
            get
            {
                if (_Items == null || MenuKey == null || MenuKey.Trim().Length == 0)
                    return null;
                for (int i = 0; i < _Items.Count; i++)
                {
                    if (_Items[i]._key == MenuKey || _Items[i]._AltKey == MenuKey)
                        return _Items[i];
                }
                return null;
            }
        }

    }

    public class SmsSessions
    {
        private List<SmsSession> _SmsSessionList;

        public SmsSessions()
        {
            _SmsSessionList = new List<SmsSession>();
        }
        public SmsSession this[string SessionName]
        {
            get
            {
                for (int i = 0; i < _SmsSessionList.Count; i++)
                {
                    if (_SmsSessionList[i].SessionName == SessionName)
                    {
                        if (_SmsSessionList[i].IsDeleted == true)
                        {
                            _SmsSessionList.RemoveAt(i);
                            return null;
                        }
                        else
                            return _SmsSessionList[i];
                    }
                }
                return null;
            }
        }
        public SmsSession this[int Index]
        {
            get
            {
                if (_SmsSessionList[Index].IsDeleted == true)
                {
                    _SmsSessionList.RemoveAt(Index);
                    return null;
                }
                else
                    return _SmsSessionList[Index];
            }
        }

        public List<SmsSession> this[SmsSessionContact Contact]
        {
            get
            {
                List<SmsSession> MatchingSessions = new List<SmsSession>();
                for (int i = 0; i < _SmsSessionList.Count; i++)
                {
                    if (_SmsSessionList[i].Contains(Contact))
                    {
                        if (_SmsSessionList[i].IsDeleted)
                        {
                            _SmsSessionList.RemoveAt(i--);
                        }
                        else
                            MatchingSessions.Add(_SmsSessionList[i]);
                    }
                }
                return MatchingSessions;
            }
        }


        public int Count
        {
            get
            {
                int i;
                for (i = 0; i < _SmsSessionList.Count; i++)
                {
                    if (_SmsSessionList[i].IsDeleted)
                        _SmsSessionList.RemoveAt(i--);
                }
                return i;
            }
        }


        public void Add(SmsSession SmsSessionItem)
        {
            if (this[SmsSessionItem.SessionName] == null)
                _SmsSessionList.Add(SmsSessionItem);
            else
                throw new Exception(String.Format("Error:Session with SessioName:{0} already exist", SmsSessionItem.SessionName));
        }

        public void Remove(SmsSession SmsSessionItem)
        {
            _SmsSessionList.Remove(SmsSessionItem);
        }

        public void Remove(String SessionName)
        {
            for (int i = 0; i < _SmsSessionList.Count; i++)
            {
                if (_SmsSessionList[i].SessionName == SessionName)
                {
                    _SmsSessionList.RemoveAt(i);
                    break;
                }
            }
        }

    }

    public class SmsSession
    {

        private String _sessionName;
        private List<SmsSessionContact> _SmsSessionContacts;
        private DateTime _sessionStartTime;
        private Boolean _isDeleted;
        private double _timeInterval;
        private Object _sessionData;
        private SmsSessionDelegate SessionDelegate;
        //public delegate void SessionDelegate(Object SessionData, String SmsBody);

        public SmsSession()
        {
            _sessionName = null;
            _SmsSessionContacts = new List<SmsSessionContact>();
            _sessionStartTime = DateTime.Now;
            _isDeleted = false;
            SessionDelegate = null;
        }

        public SmsSession(SmsSession SessionItem)
        {
            _sessionName = SessionItem.SessionName;
            _SmsSessionContacts = new List<SmsSessionContact>(SessionItem.SessionContacts);
            _sessionStartTime = SessionItem.SessionStartTime;
            _isDeleted = SessionItem.IsDeleted;
            SessionDelegate = null;
            //SessionDelegate = SessionItem.SessionDelegate;
        }

        public void AttachSessionDelegate(SmsSessionDelegate FunctionName)
        {
            SessionDelegate = new SmsSessionDelegate(FunctionName);
        }
        public SmsResponseClass CallSessionDelegate(SmsClass SmsItem)
        {
            if (SessionDelegate != null)
                return SessionDelegate(_sessionData, SmsItem);
            return null;
        }

        public bool Contains(SmsSessionContact ContactItem)
        {
            for (int i = 0; i < _SmsSessionContacts.Count; i++)
            {
                if (_SmsSessionContacts[i].Mobile == ContactItem.Mobile)
                    return true;
            }
            return false;
        }

        public object SessionUserData
        {
            get { return _sessionData; }
            set { _sessionData = value; }
        }
        public bool IsDeleted
        {
            get
            {
                if (_isDeleted == false)
                {
                    TimeSpan ts = DateTime.Now - _sessionStartTime;
                    if (ts.TotalSeconds >= _timeInterval)
                        _isDeleted = true;
                }
                return _isDeleted;
            }
        }

        public string SessionName
        {
            get { return _sessionName; }
            set { _sessionName = value; }
        }

        public void ResetTimer()
        {
            _sessionStartTime = DateTime.Now;
            _isDeleted = false;
        }

        public double TimeInterval
        {
            get { return _timeInterval; }
            set { _timeInterval = value; }
        }

        public double TimeLeft
        {
            get
            {
                if (_isDeleted == false)
                {
                    TimeSpan ts = DateTime.Now - _sessionStartTime;
                    if (ts.TotalSeconds >= _timeInterval)
                        _isDeleted = true;
                    else
                        return _timeInterval - ts.TotalSeconds;
                }
                return -1;
            }

        }
        public List<SmsSessionContact> SessionContacts
        {
            get { return _SmsSessionContacts; }
        }
        public DateTime SessionStartTime
        {
            get { return _sessionStartTime; }
        }


    }

    public class SmsSessionContact
    {
        private string _name;
        private string _mobile;

        public SmsSessionContact()
        {
            _name = "";
            _mobile = "";
        }

        public SmsSessionContact(SmsSessionContact ContactItem)
        {
            _name = ContactItem.Name;
            _mobile = ContactItem.Mobile;
        }

        public SmsSessionContact(String ContactName, String ContactMobile)
        {
            _name = ContactName;
            _mobile = ContactMobile;
        }

        public SmsSessionContact(String ContactMobile)
        {
            _name = "";
            _mobile = ContactMobile;
        }

        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        public string Mobile
        {
            get { return _mobile; }
            set { _mobile = value; }
        }

        public override string ToString()
        {
            return string.Format("{0}<{1}>", _name, _mobile);
        }

    }

}
